/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package networking;

import base.server.Broker;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import simulation.GUIOptionTransformer;

/**
 * Manipulates communication as a server
 * @author Arvanitis Ioannis
 */
public class Server implements Runnable {

    private ServerSocket providerSocket;
    private Socket connection = null;
    private ObjectOutputStream out;
    private ObjectInputStream in;
    private Object obj;
    private int port;
    private boolean connected;
    private static Broker broker;
    private int totalNodes;
    private Thread runner;

    public Server(int port) {
        try {
            this.port = port;
            //1. creating a server socket
            providerSocket = new ServerSocket(port);
            //2. Wait for connection
            print("Waiting for connection");
            connection = providerSocket.accept();
            connected = true;
            print("Connection received from " + connection.getInetAddress().getHostName());
            //3. get Input and Output streams
            out = new ObjectOutputStream(connection.getOutputStream());
            out.flush();
            in = new ObjectInputStream(connection.getInputStream());
            print("Connection successful");
        } catch (IOException ioex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
        }
        runner = new Thread(this);
        runner.start();
    }

    public void run() {
        try {
            //4. The two parts communicate via the input and output streams
            while (connected) {
                try {
                    obj = in.readObject();
                    print("client>" + obj.toString());
                    if (obj instanceof SocketMessageFactory) {
                        SocketMessageFactory smf = (SocketMessageFactory) obj;
                        if (smf.getMsgType().equals("CONNECTION_CLOSE")) {
                            connected = false;
                        } else if (smf.getMsgType().equals("BROKER_START")) {
                            //Setup the broker
                            broker = new Broker(port, smf.getTotalNodes());
                            broker.run();
                        } else if (smf.getMsgType().equals("BROKER_STOP")) {
                            //Terminate the broker
                            broker.interrupt();
                        }
                    } else if (obj instanceof GUIOptionTransformer) {
                        GUIOptionTransformer got = (GUIOptionTransformer) obj;
                        got.transformOptions();
                    }
                } catch (ClassNotFoundException cnfex) {
                    System.err.println("Data received in unknown format");
                }
            }
        } catch (IOException ioex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
        } finally {
            //4: Closing connection
            try {
                in.close();
                out.close();
                providerSocket.close();
            } catch (IOException ioex) {
                Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
            }
        }
    }

    /**
     * Send the message
     * @param msg The message to be sent
     */
    public void sendMessage(Object msg) {
        try {
            out.writeObject(msg);
            out.flush();
            print("server>" + msg.toString());
        } catch (IOException ioex) {
            Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ioex);
        }
    }

    /**
     * Prints a custom message for the server
     * @param s The string to be printed
     */
    private void print(String s) {
        Date date = new Date();
        System.out.println(" ::SERVER:: " + date.getTime() + "\tServer\t" + s);
    }
}

